// AxiosError：请求出错时error对象的类型
import axios, { AxiosError } from 'axios'
import store from '../store'
// 消息弹窗，通知提醒框
import { message, notification } from 'antd'
import { logout } from '../store/actions/user'

interface RespData {
  success: boolean
  errorCode: number
  msg?: string
  data?: any
  [key: string]: any
}

function handleError(err: AxiosError) {
  // 取消请求、请求失败都会有err
  // isCancel函数，该函数用来判断异常对象是不是取消原因对象(Cancel的实例)，返回true或false
  // 如果不是取消请求，而是请求失败
  if (!axios.isCancel(err)) {
    // response对象架构：http://www.axios-js.com/docs/#Response-Schema
    const response = err.response
    notification.error({
      message: `Error Code: ${response?.status ?? -1}`,
      description: response?.statusText ?? '服务器出小差了',
    })
  }
}

const httpInstance = axios.create({
  timeout: 5000,
  baseURL: '/api',
  // 跨域请求需要添加这行代码
  withCredentials: true,
})
// 给请求头添加默认的自定义属性
httpInstance.defaults.headers.common.isLoading = true
httpInstance.defaults.headers.common.successAlert = false
httpInstance.defaults.headers.common.errorAlert = true

// 取消请求
// 需要注意的是在get请求中CancelToken作为第二个参数传入，在post请求中CancelToken作为第三个参数传入
const CancelToken = axios.CancelToken

// 添加请求拦截器
httpInstance.interceptors.request.use(
  function (config) {
    const method = config.method
    const url = config.url
    const userState = store.getState().user.userInfo
    // 取消重复请求(并非所有请求都是取消重复请求)
    // cancelRequest是发送某些请求时手动在config.headers所添加的属性
    // 在RouterView组件中已经写好了逻辑：跳转路由取消不是当前页面的所有http请求，axiosCancelTokenStore=[]
    window.axiosCancelTokenStore?.forEach((item, index) => {
      if (
        config.headers.cancelRequest === true &&
        url === item.url &&
        method === item.method
      ) {
        item.cancel()
        // arrayObject.splice(index,amount,item1,.....,itemX)
        // splice() 方法向/从数组中添加/删除项目，然后返回被删除的项目。
        // 该方法会改变原始数组。
        window.axiosCancelTokenStore.splice(index, 1)
      }
    })
    config.headers.token = userState.token
    config.cancelToken = new CancelToken(cancel => {
      window.axiosCancelTokenStore?.push({
        pathname: window.location.pathname,
        method,
        url,
        cancel,
      })
    })
    return config
  },
  function (err) {
    handleError(err)
    return Promise.reject(err)
  },
)

// 添加响应拦截器
httpInstance.interceptors.response.use(
  function (res) {
    const headers = res.config.headers
    const data: RespData = res.data
    // 请求失败
    // httpInstance.defaults.headers.common.errorAlert = true
    if (data.success === false && headers.errorAlert) {
      notification.error({
        message: `错误码码: ${data.errorCode ?? -1}`,
        description: data.msg ?? '服务器出小差了',
      })
    }
    // headers.successAlert默认为false，即并不是所有请求都要显示成功message
    // 某些请求会在config传递headers.successAlert
    // 某些请求成功才需要提示message
    if (data.success && headers.successAlert) {
      message.success(data.msg ?? 'Success')
    }
    if (data.errorCode === 401) {
      message.info('没有访问权限，请登录~')
      setTimeout(logout, 2000)
    }
    // 因为用了TS，类型限制了只能返回res，不能返回data
    return res
  },
  function (err) {
    handleError(err)
    return Promise.reject(err)
  },
)

export default httpInstance
